package com.wmx;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.Test;

import javax.sql.DataSource;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 从 Oracle 数据库中生成 《数据库设计文档》
 * 1、亲测 Oracle 数据库生成的文档对数据长度、小数位数兼容的并不是很好。比如下面这种结果，个人感觉是不太友好的。
 * <pre>
 * 名称	        数据类型	  长度	   小数位	允许空值	  主键	默认值	说明
 * LEVEL_NUM	number	   0	    -127	   Y       N
 * START_DATE	date	   7	    0	       Y   	   N		    启用日期
 * </pre>
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2024/7/19 12:33
 */
@SuppressWarnings("Duplicates")
public class DocGeneration {

    /**
     * http://localhost:8080/doc/generation
     * 数据库表结构文档生成工具
     */
    @Test
    public void documentGeneration() {
        // 获取桌面目录作为文档存放目录, 指定生成的文件名称
        File homeDirectory = FileSystemView.getFileSystemView().getHomeDirectory();
        String fileName = "数据库设计文档";
        // 生成的文件类型：HTML-> .html，WORD-> .doc、MD-> .md
        EngineFileType fileType = EngineFileType.HTML;

        // 数据源也可以从 Spring 容器中获取，或者通过 jdbcTemplate 获取.
        // screw 1.0.5 版本时, cn.smallbun.screw.core.query.AbstractDatabaseQuery.getSchema 中会强转为 HikariDataSource
        // 所以只支持 HikariDataSource 数据源(Spring boot 默认 HikariCP 作为数据源.)
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        hikariConfig.setJdbcUrl("jdbc:oracle:thin:@10.104.65.181:1521/orcl");
        hikariConfig.setUsername("cs_element");
        hikariConfig.setPassword("1");
        // 设置可以获取tables remarks信息
        hikariConfig.addDataSourceProperty("useInformationSchema", "true");
        hikariConfig.setMinimumIdle(2);
        hikariConfig.setMaximumPoolSize(5);
        DataSource dataSource = new HikariDataSource(hikariConfig);

        // 文件生成配置
        EngineConfig engineConfig = EngineConfig.builder()
                // 生成文件存放的目录
                .fileOutputDir(homeDirectory.getAbsolutePath())
                // 生成完成是否打开输出目录
                .openOutputDir(true)
                // 生成文件类型：HTML-> .html，WORD-> .doc、MD-> .md
                .fileType(fileType)
                // 生成模板实现
                .produceType(EngineTemplateType.freemarker)
                // 自定义文件名称
                .fileName(fileName).build();

        // 忽略指定名称的表
        ArrayList<String> ignoreTableName = new ArrayList<>();
        ignoreTableName.add("test_user");
        ignoreTableName.add("test_group");
        // 忽略指定名称前缀的表
        ArrayList<String> ignorePrefix = new ArrayList<>();
        ignorePrefix.add("test_");
        // 忽略指定名称后缀的表
        ArrayList<String> ignoreSuffix = new ArrayList<>();
        ignoreSuffix.add("_test");
        ignoreSuffix.add("_backup");

        List<String> exportTables = getExportTables();

        // 数据处理配置
        ProcessConfig processConfig = ProcessConfig.builder()
                // 指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时，将生成指定表，其余表不生成、并跳过忽略表配置
                // 根据名称指定表生成
                .designatedTableName(exportTables)
                // 根据表前缀生成
                .designatedTablePrefix(new ArrayList<>())
                // 根据表后缀生成
                .designatedTableSuffix(new ArrayList<>())
                // 忽略指定名称的表
                .ignoreTableName(ignoreTableName)
                // 忽略指定名称前缀的表
                .ignoreTablePrefix(ignorePrefix)
                // 忽略指定名称后缀的表
                .ignoreTableSuffix(ignoreSuffix).build();

        // Screw 配置入口
        Configuration config = Configuration.builder()
                // 版本
                .version("1.0.0")
                // 描述
                .description("数据库设计文档生成")
                // 数据源(可以自己单独配置，也可以直接从应用中获取)
                .dataSource(dataSource)
                // 文档生成配置
                .engineConfig(engineConfig)
                // 数据处理配置
                .produceConfig(processConfig)
                .build();
        // 执行生成文档
        new DocumentationExecute(config).execute();

        // 文档文件全路径, 如 E:\桌面\数据库设计文档.html
        String fullPath = homeDirectory + File.separator + fileName + fileType.getFileSuffix();
        System.out.println("生成文档：" + fullPath);
    }

    /**
     * 获取需要导出的表名信息
     *
     * @return
     */
    private List<String> getExportTables() {
        String classPath = "doc/基础库数据库设计验收文档表名合集.txt";
        InputStream inputStream = DocGeneration.class.getClassLoader().getResourceAsStream(classPath);
        List<String> tabNames = new ArrayList<>();
        tabNames = IoUtil.readUtf8Lines(inputStream, tabNames);
        if (ObjectUtil.isEmpty(tabNames)) {
            System.err.println("目标文件中没有表名信息，请检查：" + classPath);
            return new ArrayList<>();
        }
        // 过滤空行、去掉前后空格、去重
        tabNames = tabNames.stream().filter(item -> StrUtil.isNotBlank(item)).map(item -> StrUtil.trim(item)).distinct().collect(Collectors.toList());
        // 排序
        Collections.sort(tabNames);
        return tabNames;
    }

}
